package cn.elwy.rcp.ui.dialog;

import java.util.Arrays;
import java.util.HashMap;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogBlockedHandler;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.Policy;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.PlatformUI;

import cn.elwy.common.util.AssertUtil;

/**
 * A dialog is a specialized window used for narrow-focused communication with the user.
 * <p>
 * Dialogs are usually modal. Consequently, it is generally bad practice to open a dialog without a parent. A modal
 * dialog without a parent is not prevented from disappearing behind the application's other windows, making it very
 * confusing for the user.
 * </p>
 * <p>
 * If there is more than one modal dialog is open the second one should be parented off of the shell of the first one
 * otherwise it is possible that the OS will give focus to the first dialog potentially blocking the UI.
 * </p>
 */
public class CDialog extends Window {

  /**
   * Image registry key for info message image (value <code>"dialog_messasge_info_image"</code>).
   * @since 2.0
   */
  public static final String DLG_IMG_MESSAGE_INFO = "dialog_messasge_info_image"; //$NON-NLS-1$

  /**
   * Image registry key for info message image (value <code>"dialog_messasge_warning_image"</code>).
   * @since 2.0
   */
  public static final String DLG_IMG_MESSAGE_WARNING = "dialog_messasge_warning_image"; //$NON-NLS-1$

  /**
   * Image registry key for info message image (value <code>"dialog_message_error_image"</code>).
   * @since 2.0
   */
  public static final String DLG_IMG_MESSAGE_ERROR = "dialog_message_error_image"; //$NON-NLS-1$

  /**
   * Image registry key for help image (value <code>"dialog_help_image"</code>).
   * @since 3.2
   */
  public static final String DLG_IMG_HELP = "dialog_help_image"; //$NON-NLS-1$

  /**
   * The ellipsis is the string that is used to represent shortened text.
   * @since 3.0
   */
  public static final String ELLIPSIS = "..."; //$NON-NLS-1$

  /**
   * The dialog settings key name for stored dialog x location.
   * @since 3.2
   */
  private static final String DIALOG_ORIGIN_X = "DIALOG_X_ORIGIN"; //$NON-NLS-1$

  /**
   * The dialog settings key name for stored dialog y location.
   * @since 3.2
   */
  private static final String DIALOG_ORIGIN_Y = "DIALOG_Y_ORIGIN"; //$NON-NLS-1$

  /**
   * The dialog settings key name for stored dialog width.
   * @since 3.2
   */
  private static final String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$

  /**
   * The dialog settings key name for stored dialog height.
   * @since 3.2
   */
  private static final String DIALOG_HEIGHT = "DIALOG_HEIGHT"; //$NON-NLS-1$

  /**
   * The dialog settings key name for the font used when the dialog height and width was stored.
   * @since 3.2
   */
  private static final String DIALOG_FONT_DATA = "DIALOG_FONT_NAME"; //$NON-NLS-1$

  /**
   * A value that can be used for stored dialog width or height that indicates that the default bounds should be used.
   * @since 3.2
   */
  public static final int DIALOG_DEFAULT_BOUNDS = -1;

  /**
   * Persist the last location of the dialog.
   * @since 3.2
   */
  public static final int DIALOG_PERSISTLOCATION = 0x0001;
  /**
   * Persist the last known size of the dialog.
   * @since 3.2
   */
  public static final int DIALOG_PERSISTSIZE = 0x0002;

  /**
   * The dialog area; <code>null</code> until dialog is layed out.
   */
  protected Control dialogArea;

  /**
   * The button bar; <code>null</code> until dialog is layed out.
   */
  public Composite buttonBar;

  /**
   * Collection of buttons created by the <code>createButton</code> method.
   */
  private HashMap<Integer, Button> buttons = new HashMap<Integer, Button>();

  /**
   * Font metrics to use for determining pixel sizes.
   */
  private FontMetrics fontMetrics;

  /**
   * Number of horizontal dialog units per character, value <code>4</code>.
   */
  private static final int HORIZONTAL_DIALOG_UNIT_PER_CHAR = 4;

  /**
   * Number of vertical dialog units per character, value <code>8</code>.
   */
  private static final int VERTICAL_DIALOG_UNITS_PER_CHAR = 8;

  private boolean helpAvailable;
  private String helpContextId;
  private ToolItem fHelpButton;

  public static int convertHeightInCharsToPixels(FontMetrics fontMetrics, int chars) {
    return fontMetrics.getHeight() * chars;
  }

  public static int convertHorizontalDLUsToPixels(FontMetrics fontMetrics, int dlus) {
    // round to the nearest pixel
    return (fontMetrics.getAverageCharWidth() * dlus + HORIZONTAL_DIALOG_UNIT_PER_CHAR / 2)
        / HORIZONTAL_DIALOG_UNIT_PER_CHAR;
  }

  public static int convertVerticalDLUsToPixels(FontMetrics fontMetrics, int dlus) {
    // round to the nearest pixel
    return (fontMetrics.getHeight() * dlus + VERTICAL_DIALOG_UNITS_PER_CHAR / 2) / VERTICAL_DIALOG_UNITS_PER_CHAR;
  }

  public static int convertWidthInCharsToPixels(FontMetrics fontMetrics, int chars) {
    return fontMetrics.getAverageCharWidth() * chars;
  }

  public static String shortenText(String textValue, Control control) {
    if (textValue == null) {
      return null;
    }
    GC gc = new GC(control);
    int maxWidth = control.getBounds().width - 5;
    int maxExtent = gc.textExtent(textValue).x;
    if (maxExtent < maxWidth) {
      gc.dispose();
      return textValue;
    }
    int length = textValue.length();
    int charsToClip = Math.round(0.95f * length * (1 - ((float) maxWidth / maxExtent)));
    int pivot = length / 2;
    int start = pivot - (charsToClip / 2);
    int end = pivot + (charsToClip / 2) + 1;
    while (start >= 0 && end < length) {
      String s1 = textValue.substring(0, start);
      String s2 = textValue.substring(end, length);
      String s = s1 + ELLIPSIS + s2;
      int l = gc.textExtent(s).x;
      if (l < maxWidth) {
        gc.dispose();
        return s;
      }
      start--;
      end++;
    }
    gc.dispose();
    return textValue;
  }

  public static IDialogBlockedHandler blockedHandler = new IDialogBlockedHandler() {
    public void clearBlocked() {
      // No default behaviour
    }

    public void showBlocked(IProgressMonitor blocking, IStatus blockingStatus, String blockedName) {
      // No default behaviour
    }

    public void showBlocked(Shell parentShell, IProgressMonitor blocking, IStatus blockingStatus, String blockedName) {
      // No default behaviour
    }
  };

  /**
   * Creates a dialog instance. Note that the window will have no visual representation (no widgets) until it is told to
   * open. By default, <code>open</code> blocks for dialogs.
   * @param parentShell the parent shell, or <code>null</code> to create a top-level shell
   * @wbp.parser.constructor
   */
  public CDialog(Shell parentShell) {
    this(new SameShellProvider(parentShell));
    if (parentShell == null && Policy.DEBUG_DIALOG_NO_PARENT) {
      Policy.getLog()
          .log(new Status(IStatus.INFO, Policy.JFACE, IStatus.INFO, this.getClass() + " created with no shell", //$NON-NLS-1$
              new Exception()));
    }
  }

  /**
   * Creates a dialog instance. Note that the window will have no visual representation (no widgets) until it is told to
   * open. By default, <code>open</code> blocks for dialogs.
   * @param parentShell the parent shell, or <code>null</code> to create a top-level shell
   * @wbp.parser.constructor
   */
  public CDialog(Shell parentShell, int style) {
    this(new SameShellProvider(parentShell), style);
    if (parentShell == null && Policy.DEBUG_DIALOG_NO_PARENT) {
      Policy.getLog()
          .log(new Status(IStatus.INFO, Policy.JFACE, IStatus.INFO, this.getClass() + " created with no shell", //$NON-NLS-1$
              new Exception()));
    }
  }

  /**
   * Creates a dialog with the given parent.
   * @param parentShell object that returns the current parent shell
   * @since 3.1
   */
  protected CDialog(IShellProvider parentShell) {
    super(parentShell);
    if (isResizable()) {
      setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MAX | SWT.RESIZE | getDefaultOrientation());
    } else {
      setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | getDefaultOrientation());
    }
    setBlockOnOpen(true);
  }

  /**
   * Creates a dialog with the given parent.
   * @param parentShell object that returns the current parent shell
   * @since 3.1
   */
  protected CDialog(IShellProvider parentShell, int style) {
    super(parentShell);
    setShellStyle(style | getDefaultOrientation());
    setBlockOnOpen(true);
  }

  protected void buttonPressed(SelectionEvent event) {
    buttonPressed(((Integer) event.widget.getData()).intValue(), event);
  }

  protected void buttonPressed(int buttonId, SelectionEvent event) {
    if (IDialogConstants.OK_ID == buttonId) {
      okPressed();
    } else if (IDialogConstants.CANCEL_ID == buttonId) {
      cancelPressed();
    } else {
      buttonPressed(buttonId);
    }
  }

  protected void buttonPressed(int buttonId) {

  }

  protected boolean cancelPressed() {
    setReturnCode(CANCEL);
    return close();
  }

  protected int convertHeightInCharsToPixels(int chars) {
    // test for failure to initialize for backward compatibility
    if (fontMetrics == null) {
      return 0;
    }
    return convertHeightInCharsToPixels(fontMetrics, chars);
  }

  protected int convertHorizontalDLUsToPixels(int dlus) {
    // test for failure to initialize for backward compatibility
    if (fontMetrics == null) {
      return 0;
    }
    return convertHorizontalDLUsToPixels(fontMetrics, dlus);
  }

  protected int convertVerticalDLUsToPixels(int dlus) {
    // test for failure to initialize for backward compatibility
    if (fontMetrics == null) {
      return 0;
    }
    return convertVerticalDLUsToPixels(fontMetrics, dlus);
  }

  protected int convertWidthInCharsToPixels(int chars) {
    // test for failure to initialize for backward compatibility
    if (fontMetrics == null) {
      return 0;
    }
    return convertWidthInCharsToPixels(fontMetrics, chars);
  }

  protected Button createButton(Composite parent, int id, String label, boolean defaultButton) {
    // increment the number of columns in the button bar
    ((GridLayout) parent.getLayout()).numColumns++;
    Button button = new Button(parent, SWT.PUSH);
    button.setText(label);
    button.setFont(JFaceResources.getDialogFont());
    button.setData(new Integer(id));
    button.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {
        buttonPressed(event);
      }
    });
    if (defaultButton) {
      button.setFocus();
      Shell shell = parent.getShell();
      if (shell != null) {
        shell.setDefaultButton(button);
      }
    }
    buttons.put(new Integer(id), button);
    setButtonLayoutData(button);
    return button;
  }

  protected Composite createButtonBar(Composite parent) {
    buttonBar = new Composite(parent, SWT.NONE);
    GridLayout gl_bottomArea = new GridLayout(2, false);
    gl_bottomArea.verticalSpacing = 0;
    gl_bottomArea.marginHeight = 0;
    gl_bottomArea.marginWidth = 0;
    buttonBar.setLayout(gl_bottomArea);
    buttonBar.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false, 1, 1));

    Label bottomSeparator = new Label(buttonBar, SWT.SEPARATOR | SWT.HORIZONTAL);
    bottomSeparator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));

    createHelpBar(buttonBar);

    Composite buttonComposite = new Composite(buttonBar, SWT.NONE);
    buttonComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true, 1, 1));
    GridLayout gl_buttonComposite = new GridLayout(1, false);
    gl_buttonComposite.marginRight = 10;
    gl_buttonComposite.marginHeight = 10;
    buttonComposite.setLayout(gl_buttonComposite);

    createButtonsForButtonBar(buttonComposite);

    return buttonBar;
  }

  protected Composite createHelpBar(Composite parent) {
    Composite helpBar = new Composite(parent, SWT.NONE);

    GridLayout gl_helpBar = new GridLayout(1, false);
    gl_helpBar.marginHeight = 10;
    helpBar.setLayout(gl_helpBar);
    helpBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, true, 1, 1));

    if (isHelpAvailable()) {
      if (AssertUtil.isNotEmpty(helpContextId)) {
        PlatformUI.getWorkbench().getHelpSystem().setHelp(getShell(), helpContextId);
      }
      Control helpControl = createHelpControl(helpBar);
      ((GridData) helpControl.getLayoutData()).horizontalIndent = convertHorizontalDLUsToPixels(
          IDialogConstants.HORIZONTAL_MARGIN);
    }
    return helpBar;
  }

  protected Control createHelpControl(Composite parent) {
    Image helpImage = JFaceResources.getImage(DLG_IMG_HELP);
    if (helpImage != null) {
      return createHelpImageButton(parent, helpImage);
    }
    return createHelpLink(parent);
  }

  private Link createHelpLink(Composite parent) {
    Link link = new Link(parent, SWT.WRAP | SWT.NO_FOCUS);
    ((GridLayout) parent.getLayout()).numColumns++;
    link.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
    link.setText("<a>" + IDialogConstants.HELP_LABEL + "</a>"); //$NON-NLS-1$ //$NON-NLS-2$
    link.setToolTipText(IDialogConstants.HELP_LABEL);
    link.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        helpPressed();
      }
    });
    return link;
  }

  public boolean helpPressed() {
    return true;
  }

  private ToolBar createHelpImageButton(Composite parent, Image image) {
    ToolBar toolBar = new ToolBar(parent, SWT.FLAT | SWT.NO_FOCUS);
    ((GridLayout) parent.getLayout()).numColumns++;
    toolBar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
    final Cursor cursor = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND);
    toolBar.setCursor(cursor);
    toolBar.addDisposeListener(new DisposeListener() {
      public void widgetDisposed(DisposeEvent e) {
        cursor.dispose();
      }
    });
    fHelpButton = new ToolItem(toolBar, SWT.CHECK);
    fHelpButton.setImage(image);
    fHelpButton.setToolTipText(JFaceResources.getString("helpToolTip")); //$NON-NLS-1$
    fHelpButton.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        helpPressed();
      }
    });
    return toolBar;
  }

  protected void createButtonsForButtonBar(Composite parent) {
    createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
    createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
  }

  protected void initializeBounds() {
    Shell shell = getShell();
    if (shell != null) {
      if (shell.getDisplay().getDismissalAlignment() == SWT.RIGHT) {
        // make the default button the right-most button
        Button defaultButton = shell.getDefaultButton();
        if (defaultButton != null && isContained(buttonBar, defaultButton)) {
          defaultButton.moveBelow(null);
          ((Composite) buttonBar).layout();
        }
      }
    }

    super.initializeBounds();
  }

  private boolean isContained(Control container, Control control) {
    Composite parent;
    while ((parent = control.getParent()) != null) {
      if (parent == container) {
        return true;
      }
      control = parent;
    }
    return false;
  }

  protected Control createContents(Composite parent) {
    // create the top level composite for the dialog
    Composite composite = new Composite(parent, SWT.NONE);
    GridLayout layout = new GridLayout();
    layout.marginHeight = 0;
    layout.marginWidth = 0;
    layout.verticalSpacing = 0;
    composite.setLayout(layout);
    composite.setLayoutData(new GridData(GridData.FILL_BOTH));
    applyDialogFont(composite);
    // initialize the dialog units
    initializeDialogUnits(composite);
    // create the dialog area and button bar
    dialogArea = createDialogArea(composite);

    createButtonBar(composite);

    return composite;
  }

  protected Control createDialogArea(Composite parent) {
    Composite bodyArea = new Composite(parent, SWT.NONE);
    GridLayout gl_bodyArea = new GridLayout();
    gl_bodyArea.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
    gl_bodyArea.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
    gl_bodyArea.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
    gl_bodyArea.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
    bodyArea.setLayout(gl_bodyArea);
    GridData gd_bodyArea = new GridData(GridData.FILL_BOTH);
    gd_bodyArea.heightHint = 100;
    bodyArea.setLayoutData(gd_bodyArea);
    applyDialogFont(bodyArea);
    return bodyArea;
  }

  protected Button getButton(int id) {
    return (Button) buttons.get(new Integer(id));
  }

  protected Control getButtonBar() {
    return buttonBar;
  }

  protected Control getDialogArea() {
    return dialogArea;
  }

  public static Image getImage(String key) {
    return JFaceResources.getImageRegistry().get(key);
  }

  protected Button getOKButton() {
    return getButton(IDialogConstants.OK_ID);
  }

  protected void initializeDialogUnits(Control control) {
    // Compute and store a font metric
    GC gc = new GC(control);
    gc.setFont(JFaceResources.getDialogFont());
    fontMetrics = gc.getFontMetrics();
    gc.dispose();
  }

  protected boolean okPressed() {
    setReturnCode(OK);
    return close();
  }

  protected void setButtonLayoutData(Button button) {
    GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
    int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
    Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
    data.widthHint = Math.max(widthHint, minSize.x);
    button.setLayoutData(data);
  }

  protected void setButtonLayoutFormData(Button button) {
    FormData data = new FormData();
    int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
    Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
    data.width = Math.max(widthHint, minSize.x);
    button.setLayoutData(data);
  }

  public boolean close() {
    if (getShell() != null && !getShell().isDisposed()) {
      saveDialogBounds(getShell());
    }

    boolean returnValue = super.close();
    if (returnValue) {
      buttons = new HashMap<Integer, Button>();
      buttonBar = null;
      dialogArea = null;
    }
    return returnValue;
  }

  public static void applyDialogFont(Control control) {
    if (control == null || dialogFontIsDefault()) {
      return;
    }
    Font dialogFont = JFaceResources.getDialogFont();
    applyDialogFont(control, dialogFont);
  }

  private static void applyDialogFont(Control control, Font dialogFont) {
    if (hasDefaultFont(control)) {
      control.setFont(dialogFont);
    }
    if (control instanceof Composite) {
      Control[] children = ((Composite) control).getChildren();
      for (int i = 0; i < children.length; i++) {
        applyDialogFont(children[i], dialogFont);
      }
    }
  }

  private static boolean hasDefaultFont(Control control) {
    FontData[] controlFontData = control.getFont().getFontData();
    FontData[] defaultFontData = getDefaultFont(control).getFontData();
    if (controlFontData.length == defaultFontData.length) {
      for (int i = 0; i < controlFontData.length; i++) {
        if (controlFontData[i].equals(defaultFontData[i])) {
          continue;
        }
        return false;
      }
      return true;
    }
    return false;
  }

  private static Font getDefaultFont(Control control) {
    String fontName = "DEFAULT_FONT_" + control.getClass().getName(); //$NON-NLS-1$
    if (JFaceResources.getFontRegistry().hasValueFor(fontName)) {
      return JFaceResources.getFontRegistry().get(fontName);
    }
    Font cached = control.getFont();
    control.setFont(null);
    Font defaultFont = control.getFont();
    control.setFont(cached);
    JFaceResources.getFontRegistry().put(fontName, defaultFont.getFontData());
    return defaultFont;
  }

  protected static boolean dialogFontIsDefault() {
    FontData[] dialogFontData = JFaceResources.getFontRegistry().getFontData(JFaceResources.DIALOG_FONT);
    FontData[] defaultFontData = JFaceResources.getFontRegistry().getFontData(JFaceResources.DEFAULT_FONT);
    return Arrays.equals(dialogFontData, defaultFontData);
  }

  public void create() {
    super.create();
    applyDialogFont(buttonBar);
  }

  public static IDialogBlockedHandler getBlockedHandler() {
    return blockedHandler;
  }

  public static void setBlockedHandler(IDialogBlockedHandler blockedHandler) {
    CDialog.blockedHandler = blockedHandler;
  }

  protected IDialogSettings getDialogBoundsSettings() {
    return null;
  }

  protected int getDialogBoundsStrategy() {
    return DIALOG_PERSISTLOCATION | DIALOG_PERSISTSIZE;
  }

  private void saveDialogBounds(Shell shell) {
    IDialogSettings settings = getDialogBoundsSettings();
    if (settings != null) {
      Point shellLocation = shell.getLocation();
      Point shellSize = shell.getSize();
      Shell parent = getParentShell();
      if (parent != null) {
        Point parentLocation = parent.getLocation();
        shellLocation.x -= parentLocation.x;
        shellLocation.y -= parentLocation.y;
      }
      int strategy = getDialogBoundsStrategy();
      if ((strategy & DIALOG_PERSISTLOCATION) != 0) {
        settings.put(DIALOG_ORIGIN_X, shellLocation.x);
        settings.put(DIALOG_ORIGIN_Y, shellLocation.y);
      }
      if ((strategy & DIALOG_PERSISTSIZE) != 0) {
        settings.put(DIALOG_WIDTH, shellSize.x);
        settings.put(DIALOG_HEIGHT, shellSize.y);
        FontData[] fontDatas = JFaceResources.getDialogFont().getFontData();
        if (fontDatas.length > 0) {
          settings.put(DIALOG_FONT_DATA, fontDatas[0].toString());
        }
      }
    }
  }

  protected Point getInitialSize() {
    Point result = super.getInitialSize();

    // Check the dialog settings for a stored size.
    if ((getDialogBoundsStrategy() & DIALOG_PERSISTSIZE) != 0) {
      IDialogSettings settings = getDialogBoundsSettings();
      if (settings != null) {
        // Check that the dialog font matches the font used
        // when the bounds was stored. If the font has changed,
        // we do not honor the stored settings.
        // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=132821
        boolean useStoredBounds = true;
        String previousDialogFontData = settings.get(DIALOG_FONT_DATA);
        // There is a previously stored font, so we will check it.
        // Note that if we haven't stored the font before, then we will
        // use the stored bounds. This allows restoring of dialog bounds
        // that were stored before we started storing the fontdata.
        if (previousDialogFontData != null && previousDialogFontData.length() > 0) {
          FontData[] fontDatas = JFaceResources.getDialogFont().getFontData();
          if (fontDatas.length > 0) {
            String currentDialogFontData = fontDatas[0].toString();
            useStoredBounds = currentDialogFontData.equalsIgnoreCase(previousDialogFontData);
          }
        }
        if (useStoredBounds) {
          try {
            // Get the stored width and height.
            int width = settings.getInt(DIALOG_WIDTH);
            if (width != DIALOG_DEFAULT_BOUNDS) {
              result.x = width;
            }
            int height = settings.getInt(DIALOG_HEIGHT);
            if (height != DIALOG_DEFAULT_BOUNDS) {
              result.y = height;
            }

          } catch (NumberFormatException e) {
          }
        }
      }
    }
    // No attempt is made to constrain the bounds. The default
    // constraining behavior in Window will be used.
    return result;
  }

  protected Point getInitialLocation(Point initialSize) {
    Point result = super.getInitialLocation(initialSize);
    if ((getDialogBoundsStrategy() & DIALOG_PERSISTLOCATION) != 0) {
      IDialogSettings settings = getDialogBoundsSettings();
      if (settings != null) {
        try {
          int x = settings.getInt(DIALOG_ORIGIN_X);
          int y = settings.getInt(DIALOG_ORIGIN_Y);
          result = new Point(x, y);
          // The coordinates were stored relative to the parent shell.
          // Convert to display coordinates.
          Shell parent = getParentShell();
          if (parent != null) {
            Point parentLocation = parent.getLocation();
            result.x += parentLocation.x;
            result.y += parentLocation.y;
          }
        } catch (NumberFormatException e) {
        }
      }
    }
    // No attempt is made to constrain the bounds. The default
    // constraining behavior in Window will be used.
    return result;
  }

  @Override
  protected void setShellStyle(int newShellStyle) {
    super.setShellStyle(newShellStyle);// | SWT.DIALOG_TRIM);// | SWT.APPLICATION_MODAL);
    // SWT.BORDER //建立一个有边框但没有标题栏的窗口
    // SWT.CLOSE //建立一个只有关闭按钮的窗口
    // SWT.MIN //建立一个不能最大化的窗口
    // SWT.MAX, //建立一个可以最大化最小化的窗口
    // SWT.NO_TRIM //建立一个没有任何边界和标题栏的窗口
    // SWT.RESIZE //建立一个可以改变大小的窗口
    // SWT.TITLE //建立一个没有标题栏图标，没有关闭按钮的窗口
    // SWT.ON_TOP //建立一个总是在上的窗口，注意：此属性最好与CLOSE、MIN、MAX一起使用。
    // SWT.TOOL //建立一个类似工具栏的窗口
    // SWT.APPLICATION_MODAL //建立一个APPLICATION模态窗口
    // SWT.MODELESS //建立一个非模态窗口
    // SWT.PRIMARY_MODAL //建立一个PRIMARY模态窗口
    // SWT.SYSTEM_MODAL //建立一个SYSTEM模态窗口
    // 还有两个快捷属性来建立窗口
    // SHELL_TRIM //建立一个标准模式的窗口，相当于属性设置为CLOSE | TITLE | MIN | MAX | RESIZE
    // DIALOG_TRIM //建立一个对话框模式的窗口，相当于属性设置为TITLE | CLOSE | BORDER
  }

  protected boolean isResizable() {
    return false;
  }

  public boolean isHelpAvailable() {
    return helpAvailable;
  }

  public void setHelpAvailable(boolean helpAvailable) {
    this.helpAvailable = helpAvailable;
  }

  public String getHelpContextId() {
    return helpContextId;
  }

  public void setHelpContextId(String helpContextId) {
    this.helpContextId = helpContextId;
  }

  public ToolItem getfHelpButton() {
    return fHelpButton;
  }

  public void setfHelpButton(ToolItem fHelpButton) {
    this.fHelpButton = fHelpButton;
  }

}
